// Functions associated with the Player class
//-----------------

//-----------------
// Includes libraries and other files
#include "Player.h"

//-----------------

//-----------------
//// CONSTRUCTOR - Player
Player::Player()
	: WorldObject()
{}

//// CONSTRUCTOR - Player
Player::Player( const float x, const float y, const float z)
	: WorldObject( x, y, z, true, false), mouse_invert_( 1), phi_( 1.5f), theta_( 0.0f), walking_( false), running_( false),
	height_( PLAYER_HEIGHT_CROUCH), bob_offset_( 0.0f), bob_amount_( 0.1f), bob_constraint_( bob_amount_*3), bob_y_( 0.1f)
{}
//-----------------

//-----------------
//// FUNCTION - get_phi
// retrieve the phi value of the camera orientation
float Player::get_phi() const {
	return phi_;
}

//// FUNCTION - get_theta
// retrieve the theta value of the camera orientation
float Player::get_theta() const {
	return theta_;
}

//// FUNCTION - get_look_at_x
// return the x value of the look at vector
float Player::get_look_at_x() const {
	return( get_x() + cos( get_phi()) * cos( get_theta()));
}

//// FUNCTION - get_look_at_y
// return the x value of the look at vector
float Player::get_look_at_y() const {
	return( get_y() + get_height() + sin( get_theta()));
}

//// FUNCTION - get_look_at_z
// return the x value of the look at vector
float Player::get_look_at_z() const {
	return( get_z() + sin( get_phi()) * cos( get_theta()));
}

//// FUNCTION - get_height
// return the height of the player
int Player::get_height() const {
	return height_;
}

/// FUNCTION - get_mouse_invert
// return whether the vertical control of the mouse movement has been inverted or not
int Player::get_mouse_invert() const {
	// 1 means that pushing the mouse forward will cause the player to look down
	return mouse_invert_;
}

//// FUNCTION - get_running
// return whether the player is running or not
bool Player::get_running() const {
	return running_;
}

//// FUNCTION - get_walking
// return whether the player is running or not
bool Player::get_walking() const {
	return walking_;
}

//// FUNCTION - get_score
// retrieve the player's current score
int Player::get_score() const {
	return score_;
}

//// FUNCTION - set_phi
// set the phi value of the camera orientation
void Player::set_phi( const float p) {
	phi_ = p;
}

//// FUNCTION - set_theta
// set the theta value of the camera orientation
void Player::set_theta( const float t) {
	theta_ = t;
}

//// FUNCTION - set_height
// set the height of the player
void Player::set_height( const int h) {
	height_ = h;
}

//// FUNCTION - set_mouse_invert
// set whether the mouse will be inverted or not
void Player::set_mouse_invert( const int i) {
	mouse_invert_ = i;
}

//// FUNCTION - set_walking
// set whether the player is walking or not
void Player::set_walking( const bool w) {
	walking_ = w;
}

//// FUNCTION - set_running
// set whether the player is running or not
void Player::set_running( const bool r) {
	running_ = r;
}

//// FUNCTION - move
// move the player in the desired direction
void Player::move( const char direction) {
	float x_change( 0.0f), y_change( 0.0f), z_change( 0.0f);
	float angle( 67.5f);

	// work out the amount to move by
	if( tolower( direction) == 'w' || tolower( direction) == 's') {
		x_change = (cos( phi_)   / PLAYER_MOVEMENT_FACTOR);
		y_change = (sin( theta_) / PLAYER_MOVEMENT_FACTOR);
		z_change = (sin( phi_)   / PLAYER_MOVEMENT_FACTOR);
	}
	else {
		x_change = (cos( phi_   + angle) / PLAYER_MOVEMENT_FACTOR);
		//y_change = (sin( theta_ + angle) / PLAYER_MOVEMENT_FACTOR);
		z_change = (sin( phi_   + angle) / PLAYER_MOVEMENT_FACTOR);
	}

	// halve the speed if the player is walking or crouching
	if( walking_) {
		x_change /= 2;
		y_change /= 2;
		z_change /= 2;
	}
	else
		// otherwise set run to true
		running_ = true;

	if( tolower( direction) == 'w' || tolower( direction) == 'd') {
		// add the values if the player presses w or d
		set_x( get_x() + x_change);
		set_z( get_z() + z_change);
	}
	else {
		// subtract the values if the player presses a or s
		set_x( get_x() - x_change);
		set_z( get_z() - z_change);
	}
}

//// FUNCTION - update_bob
// update the amount that the player's going up and down due to movement
void Player::update_bob( const bool& moved) {
	// Pre-conditions :- none
	assert( true);

	if( bob_offset_ > bob_constraint_) // If the offset reaches its maximum, start moving down
		bob_y_ = -bob_amount_;
	else if( bob_offset_ < -bob_constraint_) // If the offset reaches its minimum, start moving up
		bob_y_ = bob_amount_;

	if (!moved) { // If the player is not moving, move back to normal height
		if (bob_offset_ < 0) // If the offset is below 0,
			bob_y_ = bob_amount_;	// Move up to 0
		else if( bob_offset_ > 0) // If the offset is above 0,
			bob_y_ = -bob_amount_; // Move down to 0
		else
			bob_y_ = 0; // Otherwise dont move
		bob_offset_ += bob_y_; // Update the bob offset
	}
	else {
		if( bob_y_ == 0)
			bob_y_ = bob_amount_;
		bob_offset_ += bob_y_;
	}

	set_y(get_y() + bob_offset_);
}

//// FUNCTION - update_score
// increment the player's score
void Player::update_score( const int s) {
	score_ += s;
}